#include <iostream>
#include <stdlib.h>
#include <string>
#include <sys/time.h>
#include <time.h>
#include "../lib/SIGALRM_Handler.h"
#include "../lib/SignalHandler.h"
#include "../lib/Constantes.h"

#include "../lib/Logger.h"

#define PROCESS_NAME "GENERADOR_DE_PERSONAS"
#define ERROR_ARGS -1

using namespace std;

void log(string message) {
	string name = PROCESS_NAME;
	string msg = name + ": " + message;
	Logger::getInstance()->loggearLog(msg);
}

void debug(string message) {
	string name = PROCESS_NAME;
	string msg = name + ": " + message;
	Logger::getInstance()->loggearDebug(msg);
}

void sync(string message) {
	string name = PROCESS_NAME;
	string msg = name + ": " + message;
	Logger::getInstance()->loggearSynchro(msg);
}

// Pausa entre persona y persona. Valor entre 1 y MAX_SLEEP
int getSleepTime() {
	srand(time(NULL));
	// El tope para esperar a generar otra persona es MAX_SLEEP segundos
	return (rand() % MAX_SLEEP + 1);
}

string getString(int value) {
	char texto[32];
	sprintf(texto, "%d", value);
	string message = texto;
	return message;
}

std::string getTimeStamp() {
	time_t rawtime;
	struct tm * timeinfo;
	char buffer[80];

	time(&rawtime);
	timeinfo = localtime(&rawtime);
	strftime(buffer, 80, "[%d/%m/%y %H:%M:%S]\t", timeinfo);
	std::string mensaje = buffer;

	return mensaje;
}

// Inicializo el timer para controlar la cantidad de tiempo en que se generan personas
void setTimer(int tiempoAlarma) {
	string msg = "El tiempo durante el que se van a generar personas es: "
			+ getString(tiempoAlarma) + "s";
	sync(msg);
	itimerval new_value;
	new_value.it_interval.tv_sec = 0;
	new_value.it_interval.tv_usec = 0;
	new_value.it_value.tv_sec = tiempoAlarma;
	new_value.it_value.tv_usec = 0;
	itimerval old_value;
	setitimer(ITIMER_REAL, &new_value, &old_value);
	sync("Hora de inicio del timer " + getTimeStamp());
}

// Generador de personas
int main(int argc, char * argv[]) {
	/* Control de parametros
	 * 1 - tiempo de generacion de personas en segundos
	 * 2 - cantidad de pisos del edificio
	 * 3 - cantidad de ascensores
	 * 4 - capacidad del ascensor
	 * 5 - velocidad del ascensor
	 * 6 - pid del controlador central
	 * 7 - modo debug
	 * 8 - modo log
	 * 9 - modo synchro
	 * 10 - modo cout
	 */

	string msg;
	if (argc < 10) {
		cout << "Faltan parametros para instanciar el Generador de Personas."
				<< endl;
		exit(ERROR_ARGS);
	}
	// Inicializamos el logger
	Logger::getInstance()->setFlags(atoi(argv[7]), atoi(argv[8]), atoi(argv[9]),
			atoi(argv[10]));
	log("Generador de personas empieza a trabajar.");
	// Contador de personas generadas
	int cantidad = 0;
	// Contador de errores en fork
	int error = 0;
	sync("Registro el handler para la señal del timer (SIGALRM).");
	// event handler para la senial SIGALRM (-14)
	SIGALRM_Handler sigalarm_handler;
	// se registra el event handler declarado antes
	SignalHandler::getInstance()->registrarHandler(SIGALRM, &sigalarm_handler);

	msg = "Pongo la alarma para dejar de trabajar a los "
			+ getString(atoi(argv[1])) + "s";
	// Inicializo el timer
	log(msg);
	setTimer(atoi(argv[1]));
	// mientras no se reciba la senial SIGALRM, el proceso realiza su trabajo
	while (sigalarm_handler.noExpiro()) {
		pid_t persona = fork();
		// HIJO
		if (persona == 0) {
			debug("Por iniciar la persona.");
			// Generando la nueva persona
			execl("../Persona/Debug/Persona", "GeneradorDePersonas", argv[2],
					argv[3], argv[4], argv[6], argv[7], argv[8], argv[9],
					argv[10], NULL);
			// Si llego aca es porque fallo el exec
			debug("Error al iniciar la nueva persona (exec).");
			exit(0);
		}
		// PADRE
		else {
			if (persona < 0) {
				error++;
				log("Error al concebir una nueva persona (fork).");
			} else {
				cantidad++;
				log(
						"Persona N°" + getString(cantidad)
								+ " generada con éxito.");
			}
			int slp = 8;
			msg = "Duermo " + getString(slp)
					+ "s antes de generar otra persona.";
			debug(msg);
			sleep(slp);
		}
	}
	// se recibio la senial SIGALRM, el proceso deja de generar personas
	sync("Fin del timer: " + getTimeStamp());
	SignalHandler::destruir();
	log("Trabajo finalizado.");
	msg = "Se generaron " + getString(cantidad) + " personas.";
	log(msg);
	msg = "Ocurrieron " + getString(error)
			+ " errores al generar personas(fork).";
	log(msg);
	// Aviso al controlador central de que no genero mas personas
	sync("Informo al controlador central que no se generan más personas.");
	kill(atoi(argv[6]), SIGUSR1);
	sync("Controlador central informado.");
	log("Fin del generador de personas.");
	exit(0);
}
